
from multiprocessing import Process, Value
from zipfile import ZipFile

import os, sys, time, cPickle, shutil
import subprocess

from dexen.system.client.script_manager import script_executor
from dexen.system import util
from dexen.system.libs import _constants, _dexen_api
from dexen.system.libs._dexen_api import ClientAPI
from dexen.libs import dexen_api

""" GLOBALS """
running_processes = {}
states = {}
script_to_id = {}
client_api = None
url = ""

def _zipSchema(dir, zip_name):
    prev_path = os.getcwd()
    os.chdir(dir)
    
    if os.path.exists(zip_name):
        os.remove(zip_name)
    
    z = ZipFile(zip_name, "w")
        
    print "zipping files ...."
    for root, dirs, files in os.walk("."):
        #print root, dirs, files, "***\n\n"
        #if root in exception_list:
        #    continue
        if root.find(".svn") != -1:
            continue
        
        for file in files:
            if file != zip_name:
                print os.path.join(root, file)
                z.write(os.path.join(root, file))
    
    z.close()
    os.chdir(prev_path)

def _downloadSchema(schema_name):
    #print "Downloading Schema......................"
    schema = client_api.getSchema(schema_name)
    prev_path = os.getcwd()
    os.chdir(_constants._TEMP_SCHEMA_DIR)    
    if not os.path.exists(schema_name):
        os.mkdir(schema_name)
    util.unzip(schema[0], schema_name + "/") # unzip will clear everything inside first
    file = open(os.path.join(schema_name, _constants._METAFILE), "wb")
    cPickle.dump(schema[1], file)
    file.close()
    os.chdir(prev_path)

def _removeOldSchemas():
    #print "Removing Old Schema"
    schema_names = client_api.getSchemaNames()
    exception_entries = [".svn", "__init__.py", "__init__.pyc"]
    prev_path = os.getcwd()
    os.chdir(_constants._TEMP_SCHEMA_DIR)
    temp_entries = os.listdir(".")
    for entry in temp_entries:
        if entry not in schema_names \
            and entry not in exception_entries:
                util.rmentry(entry)
        if entry in schema_names and os.path.isfile(entry):
            util.rmentry(entry)
    os.chdir(prev_path)

def _getSchema(schema_name):
    prev_path = os.getcwd()
    os.chdir(_constants._TEMP_SCHEMA_DIR)
    temp_schemas = os.listdir(".") 
    if schema_name not in temp_schemas: 
        _downloadSchema(schema_name)
    else: #make sure name is a folder
        server_ts = client_api.getSchemaTimestamp(schema_name)
        file = open(os.path.join(schema_name, _constants._METAFILE), "rb")
        local_ts = cPickle.load(file)
        file.close()
        #print "timestamps:................ ", server_ts, local_ts
        import datetime
        #print datetime.datetime.fromtimestamp(server_ts)
        
        if server_ts != local_ts: # means the schema is outdated
            _downloadSchema(schema_name)
        else: 
            pass # means it is fresh copy
    os.chdir(prev_path)

""" This function is supposed to be called when the user types in the url and the connections
    is established """
def connectToServer(_url):
    global client_api, url
    print "Connecting to Server......................."
    url = _url
    client_api = ClientAPI(_url)
    _removeOldSchemas()

def createNewSchema(schema_name, schema_folder):
    """ file refers to the full absolute path """
    _zipSchema(os.path.join(_constants._SCHEMAS_DIR, schema_folder), schema_name+".zip")
    file_path = os.path.join(_constants._SCHEMAS_DIR, schema_folder, schema_name+".zip")
    f = open(file_path, "rb")
    data = f.read()
    f.close()
    """ This will delete the zip file """
    last_modified_time = os.path.getmtime(file_path) # last modified time in seconds since Epoch
    os.remove(file_path)
    message = client_api.setSchema(schema_name, data, last_modified_time)

id = 0
def runScript(schema_name, pop_name, script_name, run_times):
    """ ID is to identify each tab on the interface, when the user clicks stop the system knows 
        which one it refers to """ 
    global states, running_processes, url, id
    """ WHERE TO PUT? """
    _getSchema(schema_name)    
    file_name, function_name = client_api.getScriptFileFunctionNames(schema_name, pop_name, script_name)
    states[id] = Value('i', _constants._ALIVE)
    running_processes[id] = Process(target=script_executor, 
                               args=(schema_name, pop_name, script_name, file_name, function_name, 
                                     url, run_times, states[id]))
    script_to_id["id:%s, schema:%s, population:%s, script:%s" %(str(id), schema_name, pop_name, script_name)] = id
    running_processes[id].start() 
    id += 1

def stopScript(script_identifier):
    id = script_to_id[script_identifier]
    script_to_id.pop(script_identifier)
    states[id].value = _constants._DEAD

def runSettings(schema_name, pop_name, file_name):       
    client_api.setPopulation(schema_name, pop_name)
    dexen_api._createSettingsApi(url, schema_name, pop_name)
    """
    prev_path = os.getcwd()
    os.chdir(os.path.join(_constants.TEMP_SCHEMA_DIR, schema_name))
    proc = subprocess.Popen(["python", file_name+".py"], shell=True)
    proc.wait()
    os.chdir(prev_path)
    """    
    sys.path.append(os.path.join(_constants._TEMP_SCHEMA_DIR, schema_name))
    execfile(os.path.join(_constants._TEMP_SCHEMA_DIR, schema_name, file_name))
    sys.path.pop(len(sys.path)-1)
    
    client_api.setIndividualTable(schema_name, pop_name)

def getSchemaNames():
    return client_api.getSchemaNames()

def getPopulationNames(schema_name):
    return client_api.getPopulationNames(schema_name)

def getScriptNames(schema_name, pop_name):
    return client_api.getScriptNames(schema_name, pop_name)

def getLocalSchemaFolderNames():
    prev_path = os.getcwd()
    os.chdir(_constants._SCHEMAS_DIR)
    entries = os.listdir(".")
    exception_entries = [".svn", "__init__.py", "__init__.pyc"]
    schema_folder_names = []
    for entry in entries:
        if os.path.isdir(entry) and not (entry in exception_entries):
            schema_folder_names.append(entry)
    os.chdir(prev_path)
    return schema_folder_names

def getLocalSchemaFileNames(schema_name):
    """ BE CAREFUL """
    _getSchema(schema_name) 
    prev_path = os.getcwd()
    os.chdir(os.path.join(_constants._TEMP_SCHEMA_DIR, schema_name))
    entries = os.listdir(".")
    exception_entries = [".svn", "__init__.py", "__init__.pyc", ".dexen"]
    schema_file_names = []
    for entry in entries:
        if os.path.isfile(entry) and not (entry in exception_entries):
            schema_file_names.append(entry)
    os.chdir(prev_path)
    return schema_file_names

def _updateRunnigScriptList():
    for key in script_to_id.keys()[:]:
        if states[script_to_id[key]].value == _constants._DEAD:
            script_to_id.pop(key)
            
def getLocalRunningScripts():
    _updateRunnigScriptList()
    return script_to_id.keys()